<?php
declare (strict_types=1);

namespace addons\BuilderPlus\driver;

use addons\BuilderPlus\exception\BuilderException;
use addons\BuilderPlus\facade\Table;
use app\common\tool\Result;

class View extends \think\facade\View
{
    private const DS = DIRECTORY_SEPARATOR;

    private string $template;

    private string $addTemplate;

    private string $editTemplate;

    private string $viewPath;

    public array $formConfig = [];

    public array $defFormConfig = [
        'title'       => '',
        'name'        => '',
        'value'       => '',
        'options'     => '',
        'md'          => 6,
        'remark'      => '',
        'suffix'      => '',
        'placeholder' => '',
        'req'         => false
    ];

    public function __construct()
    {
        $this->viewPath = app()->getRootPath() . 'addons' . self::DS . 'BuilderPlus' . self::DS . 'view' . self::DS;
        $this->template = $this->viewPath . 'index.html';
        $this->addTemplate = $this->viewPath . 'add.html';
        $this->editTemplate = $this->viewPath . 'add.html';
        $this->formConfig = $this->defFormConfig;
    }

    public function fetchIndex($components)
    {

        $appendTpl = [$this->viewPath . 'tpl' . self::DS . 'builder'];

        if (!empty($components['right_buttons'])
            && $components['toolbar'] == Table::getConfig('defaultToolBar')) {
            $appendTpl[] = $this->viewPath . 'tpl' . self::DS . 'toolbar';
        }
        if (!empty($components['tpl'])) {
            foreach ($components['tpl'] as $tpl) {
                $appendTpl[] = app()->getAppPath() . '/tpl/' . $tpl;
            }
        }

        $assignKey = [
            'top_buttons', 'right_buttons', 'search_items', 'search_tab_items',
            'columns', 'fastSort', 'fastRatio', 'friendly', 'switch', 'withImgTpl', 'withVideoTpl'
        ];
        $assign = [];
        foreach ($assignKey as $val) {
            $assign[$val] = $components[$val];
        }
        return View::fetch($this->template, array_merge($assign, [
            'builderToken' => $components['token'],
            'builderUrl'   => $components['url'],
            'builderPk'    => $components['builderPk'],
            'builderTpl'   => $this->getTpl($components, $appendTpl),
        ]));
    }

    public function fetchAdd($param, $options, $tpl)
    {
        try {
            $arguments = Table::getCache($param['builderTableToken']);
            if (empty($arguments)) {
                throw new BuilderException('加载失败');
            }

            if (request()->isAjax()) {
                return Result::success('success', $arguments['columns']);
            }

            $html = "";
            foreach ($arguments['columns'] as $column) {
                if (!empty($column['editCol'])) {
                    $html .= $this->getModules($column['field'], $column['title'], $column['editCol']);
                }
            }

            return View::assign([
                'html'              => $html,
                'builderTableToken' => $param['builderTableToken'],
                'navTitle'          => $arguments['menu']['s_nav'],
                'pk'                => $options['pk'],
                'just'              => isset($options['just']) ? ($options['just'] ? 'true' : 'false') : 'true'
            ])->fetch($tpl ?: $this->addTemplate);
        } catch (\Exception $e) {
            return View::fetch(app()->getBasePath() . '/error/empty.html', [
                'msg' => $e->getMessage(),
            ]);
        }

    }

    public function fetchEdit($param, $options, $tpl)
    {
        try {
            $arguments = Table::getCache($param['builderTableToken']);
            if (empty($arguments)) {
                throw new BuilderException('加载失败');
            }

            if (request()->isAjax()) {
                return Result::success('success', $arguments['columns']);
            }

            $info = $options['model']::where($options['pk'], $param['id'])->find();

            $html = "";
            if (!$tpl) {
                foreach ($arguments['columns'] as $column) {
                    if (!empty($column['editCol']) && $column['editCol']['type'] > 1) {

                        $html .= $this->getModules($column['field'], $column['title'], $column['editCol'], $info);
                    }
                }
            }

            return View::assign([
                'info'              => $info,
                'html'              => $html,
                'builderTableToken' => $param['builderTableToken'],
                'navTitle'          => $arguments['menu']['s_nav'],
                'pk'                => $options['pk'],
                'just'              => isset($options['just']) ? ($options['just'] ? 'true' : 'false') : 'true'
            ])->fetch($tpl ?: $this->editTemplate);

        } catch (\Exception $e) {
            return View::fetch(app()->getBasePath() . '/error/empty.html', [
                'msg' => $e->getMessage(),
            ]);
        }

    }

    public function builderFormInit($options)
    {
        $this->formConfig = $this->defFormConfig;
        foreach ($options as $key => $val) {
            if (isset($this->formConfig[$key]) && $this->formConfig[$key] != $val) {
                $this->formConfig[$key] = $options[$key];
            }
        }
        return $this;
    }

    public function getFormItemInputHtml($type = 'text', $append = '', $disabled = false): string
    {
        $dis = $disabled ? 'disabled' : '';
        $t = 'block';
        $dt = '';
        $require = $this->formConfig['req'] ? 'lay-verify="req"' : '';
        if ($type == 'number') {
            $t = 'inline';
            if ($this->formConfig['suffix'] == '%') {
                $this->formConfig['value'] = $this->formConfig['value'] ? $this->formConfig['value'] * 100 : $this->formConfig['value'];
                $dt = 'data-type="ratio"';
            }
        }
        $placeholder = !empty($this->formConfig['placeholder']) ? $this->formConfig['placeholder'] : "请填写{$this->formConfig['title']}";
        $tag = $this->getOpenClose($t);
        $html = $tag['open'];
        $html .= <<<HTML
                    <input type="{$type}" 
                        {$dt}
                        {$require}
                        name="{$this->formConfig['name']}" 
                        value="{$this->formConfig['value']}"  
                        placeholder="{$placeholder}" 
                        autocomplete="off" 
                        class="layui-input" {$dis}
                    />
            HTML;
        if ($append) $html .= $append;
        $html .= $tag['close'];
        return $html;

    }

    public function getFormItemImgHtml($num = 1, $url = '', $type = 'images'): string
    {
        $url = $url ?: url($type == 'images' ? 'uploads/image' : 'uploads/video');
        $tag = $this->getOpenClose();
        $html = $tag['open'];
        $html .= <<<HTML
                 <div class="builder-preload"
                     data-url="{$url}"
                     data-field="{$this->formConfig['name']}"
                     data-format="{$type}"
                     data-num="{$num}"
                     data-val="{$this->formConfig['value']}"
                 ></div>
            HTML;
        $html .= $tag['close'];
        return $html;
    }

    public function getFormItemEditorHtml($url = ''): string
    {
        $field = $this->formConfig['name'];
        $url = $url ?: url('uploads/editor');
        $tag = $this->getOpenClose();
        $html = $tag['open'];
        $html .= <<<HTML
                <div  data-format='editor' 
                      data-filed="{$field}" id="editor—wrapper" class="builder-preload wang-editor editor—wrapper"
                      data-value='{$this->formConfig['value']}' data-upload='{$url}'>
                    <input type="hidden" class="editor—{$field}" name="{$field}" value='{$this->formConfig['value']}' />
                    <div class="toolbar-container" id="toolbar-container-{$field}"><!-- 工具栏 --></div>
                    <div class="editor-container" id="editor-container-{$field}"><!-- 编辑器 --></div>
                </div>
            HTML;
        $html .= $tag['close'];
        return $html;
    }

    public function getFormItemSelectHtml($filter = ''): string
    {
        $layFilter = $filter ? "lay-filter='{$filter}'" : '';
        $tag = $this->getOpenClose('inline');
        $html = $tag['open'];
        $html .= "<select id='{$this->formConfig['name']}' name='{$this->formConfig['name']}' lay-search {$layFilter}>";

        foreach ($this->formConfig['options'] as $key => $item) {
            $selected = ($this->formConfig['value'] && $this->formConfig['value'] == $key) ? 'selected' : '';
            $html .= "<option {$selected} value='{$key}'>{$item}</option>";
        }
        $html .= '</select>' . $tag['close'];
        return $html;
    }

    public function getFormItemTextareaHtml(): string
    {
        $require = $this->formConfig['req'] ? 'lay-verify="req"' : '';
        $tag = $this->getOpenClose();
        $html = $tag['open'];
        $html .= <<<HTML
                    <textarea type="text" rows="4" name="{$this->formConfig['name']}" {$require} placeholder="请填写{$this->formConfig['title']}"  class="layui-textarea">{$this->formConfig['value']}</textarea>
            
            HTML;
        $html .= $tag['close'];
        return $html;
    }

    public function getFormItemTimeHtml($format, $range = false): string
    {
        $require = $this->formConfig['req'] ? 'lay-verify="req"' : '';
        $range = $range ? 'data-range' : '';
        $tag = $this->getOpenClose($format == 'datetime' ? 'block' : 'inline');
        $html = $tag['open'];
        $html .= <<<HTML
                   <input placeholder="点击选择{$this->formConfig['title']}" type='text' 
                            {$require}
                            data-format='{$format}' 
                            data-type='layDate' 
                            $range
                            name="{$this->formConfig['name']}"
                            value='{$this->formConfig['value']}'
                            class='layui-input builder-preload'
                            autocomplete="off"
                            readonly>
            HTML;
        $html .= $tag['close'];
        return $html;
    }

    public function getFormItemCheckBoxHtml($type = 'checkbox', $filter = '')
    {
        $tag = $this->getOpenClose();
        $layFilter = $filter ? "lay-filter='{$filter}'" : '';
        $html = $tag['open'];
        $val = explode(',', strval($this->formConfig['value']));
        foreach ($this->formConfig['options'] as $key => $item) {
            $checked = in_array($key, $val) ? 'checked' : '';
            $html .= "<input {$layFilter} type='{$type}' name='{$this->formConfig['name']}' title='{$item}' value='{$key}' $checked>";
        }
        $html .= $tag['close'];
        return $html;
    }

    public function getOpenClose($t = 'block'): array
    {
        $w = $t == 'block' ? '' : 'style="width: 190px;position: relative"';
        $close = '';
        if ($this->formConfig['suffix']) {
            $close .= '<div class="layui-input-split layui-input-suffix" style="line-height: 38px;font-size: 13px;color: #515a6e">' . $this->formConfig['suffix'] . '</div>';
        }
        $open = <<<HTML
            <div class="layui-col-xs12 layui-col-sm12 layui-col-md{$this->formConfig['md']}" id='builder-{$this->formConfig['name']}'>
                <div class="layui-form-item">
                    <label class="layui-form-label">{$this->formConfig['title']}</label>
                    <div class="layui-input-block" ><div $w>
            HTML;


        if ($this->formConfig['remark']) {
            $close .= '</div><div class="layui-form-mid layui-text-em">* ' . $this->formConfig['remark'] . '</div></div></div></div>';
        } else {
            $close .= '</div></div></div></div>';
        }
        return ['open' => $open, 'close' => $close];
    }

    public function getModules(string $field, string $title, array $editCol, object|array $info = null): string
    {
        $html = '';
        $html .= "<div class='layui-col-xs12 layui-col-sm12 layui-col-md6' id='builder-{$field}'>";
        $html .= "<div class='layui-form-item'>";
        $html .= "<label class='layui-form-label'>{$title}</label>";

        $place = "name='{$field}'  placeholder='请填写{$title}' autocomplete='off'";
        $class = 'layui-input-block';
        $main = '';
        $append = '';
        $style = '';
        $initValue = '';
        $require = $editCol['require'] ? 'lay-verify="req"' : '';

        if ($editCol['format'] == 'linkage' && !empty($info)) {
            $ex = explode('-', $field);
            $v = [];
            $init = [];
            foreach ($ex as $str) {
                $init[] = $info->$str;
                $v[] = $info->{$str . 'With'}->title;
            }
            $value = implode('-', $v);
            $initValue = implode('-', $init);

        } else {
            $value = !empty($info) ? $info->getData($field) : '';
        }

        switch ($editCol['format']) {
            case "text":
            case "number":
            case "password":
                $value = $editCol['format'] == 'password' ? '' : $value;
                $main = "<input type='{$editCol['format']}' {$place} class='layui-input' {$require} value='{$value}'>";
                break;
            case "textarea":
                $main = "<textarea {$place} class='layui-textarea' {$require}>{$value}</textarea>";
                break;
            case "year":
            case "month":
            case "date":
            case "time":
            case "datetime":
                $range = $editCol['dateRange'] ? 'data-range' : '';
                $main = <<<HTML
                            <input type='text' {$place}  
                            data-format='{$editCol['format']}' 
                            data-type='layDate' 
                            {$range}
                            class='layui-input builder-preload' {$require}
                            readonly
                            value='{$value}'>
                            HTML;
                break;
            case "ratio":
                $class = 'layui-input-inline';
                $main = "<input data-type='ratio' type='number' {$place} class='layui-input' {$require} value=" . ($value * 100) . ">";
                $append = "<div class='layui-form-mid layui-word-aux'>%</div>";
                break;
            case "checkbox":
            case "radio":
                if (empty($editCol['value'])) break;
                $index = 0;
                foreach ($editCol['value'] as $key => $item) {
                    $checked = $value && strpos(strval($value), strval($key)) !== false ? 'checked' : '';
                    if ($editCol['format'] == "radio") {
                        $checked = (!$checked && !$index) ? 'checked' : $checked;
                    }
                    $main .= "<input {$checked} lay-filter='{$field}' type='{$editCol['format']}' name='{$field}' title='{$item}' value='{$key}' {$require}>";
                    $index++;
                }
                break;
            case "select":
                $main .= "<select name='{$field}' lay-search {$require} lay-filter='{$field}'>";
                foreach ($editCol['value'] as $key => $item) {
                    $selected = $value && $value == $key ? 'selected' : '';
                    $main .= "<option {$selected} value='{$key}'>{$item}</option>";
                }
                $main .= "</select>";
                break;
            case "editor":
                $style = 'word-break: break-all;';
                $main = <<<HTML
                            <div  data-format='editor' 
                                    data-filed="{$field}" id="editor—wrapper" class="builder-preload wang-editor editor—wrapper"
                                 data-value='{$value}' data-upload='{$editCol['upload']}'>
                                <input type="hidden" class="editor—{$field}" name="{$field}" value=''  {$require}/>
                                <div class="toolbar-container" id="toolbar-container-{$field}"><!-- 工具栏 --></div>
                                <div class="editor-container" id="editor-container-{$field}"><!-- 编辑器 --></div>
                            </div>
                            HTML;
                break;
            case "images":
            case "video":
                $value = !empty($info) ? $info->$field : '';
                $main = <<<HTML
                               <div class="builder-preload"
                                     data-url="{$editCol['upload']}"
                                     data-field="{$field}"
                                     data-format="{$editCol['format']}"
                                     data-num="{$editCol['maxNum']}"
                                     data-val="{$value}"
                                     ></div>
                            HTML;

                break;
            case "linkage":
                $main = <<<HTML
                <div class="linkage">
                    <input type="text" placeholder="点击选择{$title}"
                           data-field="{$field}"
                           data-url="{$editCol['linkageUrl']}"
                           data-val="{$initValue}"
                           class="layui-input lay-search-linkage"
                           id="lay-search-linkage-$field"
                           value="{$value}" autocomplete="off" readonly >
                </div>
                HTML;

                break;


        }

        $html .= "<div class='{$class}' style='{$style}'>";
        $html .= $main;
        $html .= "</div>";
        $html .= $append;
        $html .= "</div>";
        $html .= "</div>";

        return $html;
    }

    private function getTpl(array $components, array $tpl = [])
    {
        $html = '';
        View::assign($components);
        foreach ($tpl as $v) {
            $html .= View::fetch($v . '.tpl');
        }
        $html .= View::fetch(app()->getAppPath() . '/tpl/common.tpl');
        return $html;
    }
}